namespace Viyi.Util.Extensions;

public static partial class ObjectExtensions {
    /// <summary>调用 `fn`，并返回自身</summary>
    /// <remarks>
    /// 通常用于在函数试编程中的链式调用，
    /// 也常使用 `?.` 调用来排除调用者值为 `null` 的情况。
    /// </remarks>
    public static T Also<T>(this T it, Action<T> fn) {
        fn(it);
        return it;
    }

    /// <summary>调用 `fn`，并返回自身</summary>
    /// <remarks>
    /// 通常用于在函数试编程中的链式调用，
    /// 也常使用 `?.` 调用来排除调用者值为 `null` 的情况。
    /// </remarks>
    public static T Also<T, R>(this T it, Func<T, R> fn) {
        fn(it);
        return it;
    }

    /// <summary>调用 `fn`，并返回自身</summary>
    public static ref T RefAlso<T>(ref this T it, Action<T> fn) where T : struct {
        fn(it);
        return ref it;
    }

    /// <summary>调用 `fn`，并返回自身</summary>
    public static ref T RefAlso<T, R>(ref this T it, Func<T, R> fn) where T : struct {
        fn(it);
        return ref it;
    }

    /// <summary>调用 `fn`，并返回自身</summary>
    /// <remarks>
    /// 通常用于在函数试编程中的链式调用，
    /// 也常使用 `?.` 调用来排除调用者值为 `null` 的情况。
    /// </remarks>
    public static ref T? RefAlso<T>(ref this T? it, Action<T?> fn) where T : struct {
        fn(it);
        return ref it;
    }

    /// <summary>调用 `fn`，并返回自身</summary>
    /// <remarks>
    /// 通常用于在函数试编程中的链式调用，
    /// 也常使用 `?.` 调用来排除调用者值为 `null` 的情况。
    /// </remarks>
    public static ref T? RefAlso<T, R>(ref this T? it, Func<T?, R> fn) where T : struct {
        fn(it);
        return ref it;
    }

    /// <summary>Also 的异步版本</summary>
    public static async ValueTask<T> AlsoAsync<T>(this T it, Func<T, ValueTask> fn) {
        await fn(it);
        return it;
    }
}
